home *** CD-ROM | disk | FTP | other *** search
File List | 1989-12-13 | 6.6 KB | 290 lines |
- _DEBUGGING C PROGRAMS_
- by Bob Edgar
-
- [LISTING ONE]
-
- short tlevel = 0;
-
- main(argc, argv, envp)
- char *argv[];
- char **envp;
- {
- int n;
-
- for (n = 0; n < argc; n++)
- {
- if (argv[n][0] == '-' && argv[n][1] == 'L')
- {
- int i;
- char digit;
-
- /* Found -L argument - process it */
-
- digit = argv[n][2];
- if (digit < '0' || digit > '9')
- {
- printf("Bad -L option\n");
- exit(1);
- }
- tlevel = digit - '0';
-
- /* Delete this element from argv[]. */
- /* We assume that argv[] has argc+1 */
- /* elements (most systems set argv[argc] */
- /* to zero). */
-
- argc--;
- for (i = n; i < argc; i++)
- argv[i] = argv[i+1];
- }
- }
- mymain(argc, argv, envp);
- }
-
-
- [LISTING TWO]
-
- /* showstack: Show layout of host machine's stack */
-
- #define STACKLOW 1
- int *stacktop, *ip;
- int f(), g();
-
- main(argc, argv)
- char **argv;
- {
- stacktop = (int *) &argv;
- printf("&argc=%08lx &argv=%08lx\n", &argc, &argv);
- printf("&main=%08lx &f=%08lx &g=%08lx\n", main, f, g);
- f(0x11112222, 0x33334444);
- }
-
- f(arg_1, arg_2)
- {
- g(0x55556666);
- }
-
- g(arg_2)
- {
- int local;
-
- local = 0x77778888;
- #ifdef STACKLOW /* Stack grows towards LOWER addresses */
- for (ip = stacktop; ip >= &local; ip--)
- #else /* Stack grows towards HIGHER addresses */
- for (ip = stacktop; ip <= &local; ip++)
- #endif
- printf("%08lx\t%08x\n", ip, *ip);
- }
-
-
-
- [LISTING THREE]
-
- calltrace(arg_1) /* Trace calling sequence */
- {
- int *bp, *newbp;
-
- bp = (int *) (&arg_1 - 2);
-
- while (bp < stacktop) /* "<" because STACKLOW */
- {
- newbp = (int *) *bp; /* next link in list */
- printf("BP=%08lx RET. ADDR=%08lx\n", bp, *(bp + 1));
- bp = newbp;
- }
- }
-
-
-
- [LISTING FOUR]
-
-
- struct func
- {
- int (*addr)();
- char *name;
- };
-
- int main(), f(), g();
-
- struct func funcs[] = /* symbol table */
- {
- main, "main",
- f, "f",
- g, "g",
- };
-
- int nfuncs = sizeof(funcs)/sizeof(funcs[0]);
-
- char *atoname(a) /* convert address to function name */
- int (*a)(); /* address */
- {
- char *s;
- int (*maxa)();
- int n;
-
- maxa = 0;
- s = "?";
- for (n = 0; n < nfuncs; n++)
- if (funcs[n].addr < a && funcs[n].addr > maxa)
- s = funcs[n].name, maxa = funcs[n].addr;
- return s;
- }
-
-
- Example 1: Defining the NDEBUG macro
-
- #ifndef NDEBUG
- #define assert(cond) {if (!(cond)) \
- printf("ASSERT cond, file %s line %d\n", \
- __FILE__, __LINE__); exit(1);}
- #else
- #define assert(cond) {;} /* Empty block */
- #endif
-
-
- Example 2: Using an assertion
-
- do_str(s)
- char *s;
- {
- assert(s != NULL)
- /* rest of do_str... */
-
-
-
- Example 3: using parentheses so that the entire arugment list to
- printf is a single argument
-
- #define assertp(cond, args) {if (!(cond)) \
- printf("ASSERT cond, file %s, line %d\n", \
- __FILE__, __LINE__); \
- printf args; exit(1);}
-
-
- Example 4: A typical use of assert
-
- assertp(n > 3, ("Surprise! n > 3, is %d\n", n))
-
-
- Example 5: A macro which unconditionally prints when the trace
- level is high enough
-
- #define assertl(level, args) {if (tlevel >= (level)) \
- printf("file %s, line %d\n", \
- __FILE__, __LINE__); \
- printf args; exit(1);}
-
-
- Example 6: A typical use of Example 5
-
- assertl(2, ("i=%d j=%d\n", i, j))
-
-
- Example 7: An assert.h header file
-
- #ifndef NDEBUG
- extern short tlevel;
- #define main mymain
- #endif
-
-
- Example 8: Typical bit definitions
-
- #define TBIT_LEXER 0x0001 /* Lexical analysis functions */
- #define TBIT_PARSER 0x0002 /* Parser */
- #define TBIT_EXPTREE 0x0004 /* Expression tree */
- #define TBIT_CODEGEN 0x0008 /* Code generator */
- #define TBIT_OPTIM 0x0010 /* Optimizer */
-
-
- Example 9: Defining assert-like macros
-
- #define assertb(bits, args) {if ((bits) & tbits) \
- printf args;}
-
- which can be used in this way:
-
- assertb(TBITS_PARSER | TBITS_EXPTREE,
- ("Nodes in expression tree = %d\n", nnode))
-
-
- Example 10: Adding a statement to trap an error
-
- do_str(s)
- char *s;
- {
- if (s == NULL)
- printf("do_str(NULL)!\n");
-
-
- Example 11: A function for a calling function
-
- do_str(s)
- char *s;
- {
- char *caller();
- if (s == NULL)
- printf("%s() calls do_str(NULL)\n", caller());
- }
-
-
- Example 12: Calling a function
-
-
- push n'th argument
- ...
- push 2nd argument
- push 1st argument
- push current instruction pointer (ie. return address)
- jump to start of function
- copy stack pointer (SP) to base pointer (BP)
- push BP
-
-
- Example 13: The top of the stack after functions have been called
-
- 2nd arg
- 1st arg
- Return addr.
- BP--> Caller's BP
-
-
- Example 14: Modifying showstack so that g() calls only ctrace()
- results in this output
-
- &main=00000094 &f=000000db &g=000000f9
- BP=0187ed20 RET. ADDR=0000010a
- BP=0187ed38 RET. ADDR=000000f1
- BP=0187ed50 RET. ADDR=000000d3
- BP=0187ed6c RET. ADDR=0000057d
-
-
- Example 15: The function atoname() finds the function closest to,
- but starting before, the address given as its argument.
-
- printf("BP=%08lx FUNCTION=%s\n", bp, atoname(*(bp + 1)));
-
- then the output looks like this:
-
- &main=00000094 &f=000000db &g=000000f9
- BP=0187ed28 FUNCTION=g
- BP=0187ed40 FUNCTION=f
- BP=0187ed58 FUNCTION=main
- BP=0187ed74 FUNCTION=g
-
-
- Example 16: Changing ctrace() again
-
- printf("%s(%x, %x)\n", atoname(*(bp + 1)), *(newbp + 2), *(newbp + 3));
-
- After this change, the output of the test program became:
-
- &main=00000094 &f=000000db &g=000000f9
- g(55556666, 187eda8)
- f(11112222, 33334444)
- main(1, 187eda8)
- g(1, 187ee20)
-